package com.hzlj.position.config.rest.operator.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fz.common.base.core.JsonUtils;
import com.fz.common.base.core.LocateUtils;
import com.google.common.collect.Maps;
import com.hzlj.position.config.common.dto.common.PositionAddDTO;
import com.hzlj.position.config.common.dto.operatorConfig.OperatorConfigQueryResultDTO;
import com.hzlj.position.config.common.enums.WarningType;
import com.hzlj.position.config.rest.operator.OperatorLocateRest;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

/**
 * 电信
 * L1 协议
 *
 * @author lifh
 **/
@Slf4j
@Service("unicomCloudTraceLocate")
public class UnicomCloudTraceLocate implements OperatorLocateRest {

    @Override
    public PositionAddDTO fetchPosition(OperatorConfigQueryResultDTO config,
                                        String jgCode,
                                        String telephone,
                                        BiFunction<String, String, String> dictFun) {
        String uri = "/trace-api/openApi/location";
        //配置请求参数
        Map<String, Object> params = MapUtil.<String, Object>builder()
                .put("number", telephone)
                .put("returnType", 2)
                .build();
        log.debug("运营商-{}-请求参数：{}", operatorName(), telephone);
        String requestResult;
        try {
            Map<String, String> header = getHeader(config, uri);
            requestResult = HttpRequest.post(config.getLocateRequestUrl() + uri)
                    .headerMap(header, true)
                    .header("Content-type", "application/json")
                    .timeout(FETCH_LOCATE_TIMEOUT)
                    .body(JsonUtils.obj2json(params))
                    .execute()
                    .body();
        } catch (Exception e) {
            log.error("运营商-{}-定位请求失败：{}->{}", operatorName(), telephone, JsonUtils.obj2json(params), e);
            throw e;
        }

        PositionAddDTO position = defaultPosition(telephone, config);
        position.setWarningType(WarningType.FAIL.getCode());

        if (ObjectUtil.isEmpty(requestResult)) {
            log.warn("运营商-{}-请求结果：{}->{}", operatorName(), telephone, requestResult);
            return position;
        }

        try {
            log.info("运营商-{}-请求结果：{}->{}", operatorName(), telephone, requestResult);
            LocateResult locateResult = JsonUtils.json2obj(requestResult, LocateResult.class);
            String code = locateResult.getCode();
            WarningType warningType = config.getExt().checkWarningType(code);
            if (warningType != null) {
                position.setWarningType(warningType.getCode());
            }

            //设置错误码
            position.setOperatorReturnCode(code);
            //经纬度
            String longitude = locateResult.getLongitude();
            String latitude = locateResult.getLatitude();

            //没有位置信息,则直接返回
            if (!"1".equals(code) || ObjectUtil.hasEmpty(latitude, longitude)) {
                position.setPosition(StrUtil.format("【{}】{}", code, StrUtil.emptyToDefault(locateResult.getMessage(), "未知错误")));
                return position;
            }

            String[] formatLatOrLon = formatLatOrLon(longitude, latitude);
            position.setLongitude(formatLatOrLon[0]);
            position.setLatitude(formatLatOrLon[1]);
            position.setPosition(
                    locateResult.getAddress()
            );
            position.setWarningType(WarningType.SUCCESS.getCode());
            position.setPositionTime(new Date());
        } catch (Exception e) {
            log.error("定位解析失败：telephone={},result={}", telephone, requestResult, e);
            position.setPosition(StrUtil.format("【{}】{}", "-1", "定位失败"));
        }
        return position;
    }


    @Override
    public String operatorName() {
        return "联通";
    }

    @Override
    public String operatorDictType() {
        return "LOCATE_UNICOM_CLOUD_TRACE";
    }

    private String[] formatLatOrLon(String lon, String lat) {
        double[] latOrLon = LocateUtils.gcjTo84(Double.parseDouble(lon), Double.parseDouble(lat));
        return new String[]{
                BigDecimal.valueOf(latOrLon[0]).setScale(6, RoundingMode.HALF_EVEN).toPlainString(),
                BigDecimal.valueOf(latOrLon[1]).setScale(6, RoundingMode.HALF_EVEN).toPlainString()
        };
    }

    @Data
    @NoArgsConstructor
    public static class LocateResult {
        @JsonProperty("code")
        private String code;
        @JsonProperty("message")
        private String message;
        @JsonProperty("address")
        private String address;
        @JsonProperty("latitude")
        private String latitude;
        @JsonProperty("localTime")
        private String localTime;
        @JsonProperty("longitude")
        private String longitude;
        @JsonProperty("number")
        private String number;
    }

    private Map<String, String> getHeader(OperatorConfigQueryResultDTO config, String path) {
        String timestamp = System.currentTimeMillis() + "";
        String version = "1.0.0";
        Map<String, String> params = Maps.newTreeMap();
        params.put("timestamp", timestamp); //timestamp 为毫秒数的字符串形式
        params.put("path", path);
        params.put("version", version);

        String locateRequestConfig = config.getLocateRequestConfig();
        JSONObject json = JSONUtil.parseObj(locateRequestConfig);
        //获得sign
        final String sign = params.entrySet().stream()
                .map(entry -> String.join("", entry.getKey(), entry.getValue())).
                collect(Collectors.joining())
                .trim()
                .concat(json.getStr("signKey"));
        //头
        return MapUtil.<String, String>builder()
                .put("timestamp", timestamp)
                .put("version", version)
                .put("appKey", json.getStr("appKey"))
                .put("sign", DigestUtils.md5DigestAsHex(sign.getBytes()).toUpperCase())
                .build();
    }


    public static void main(String[] args) {
        UnicomCloudTraceLocate unicomCloudTraceLocate = new UnicomCloudTraceLocate();
        OperatorConfigQueryResultDTO config = new OperatorConfigQueryResultDTO();
        config.setLocateRequestUrl("http://122.13.7.98:12288/new_api");
//        config.setLocateRequestUrl("http://10.41.81.141:12288/new_api");
        config.setLocateRequestConfig(JsonUtils.obj2json(
                MapUtil.<String, String>builder()
                        .put("appKey", "3BK7S52XMUF8QZKOABNZKA643JVRWELO")
                        .put("signKey", "U30QIU5XNCPN4FSWG5SGH58CXNCKV3PX")
                        .build()
        ));

        PositionAddDTO positionAddDTO = unicomCloudTraceLocate.fetchPosition(config,
                "1",
                "18620214105",
                (type, code) -> {
                    return type + ":" + code;
                });
        System.out.println(positionAddDTO);

    }

}
